#include "Gui_Handler.h"
#include "../Engine/Engine.h"
#include "../Engine/Networking.h"
#include "Item/ItemFactory.h"
using namespace wordModify;

#define addAsset Engine::Ins()->graphics.AddAsset
#define TpMenuList ((gui_panel*)(menuList[i]))
#define TiMenuList ((gui_input*)(menuList[i]))
#define TbMenuList ((gui_button*)(menuList[i]))

/*=====PRIVATE INITS=====*/
void GUI_Handler::initAssets()
{
	assets[sAlpha]				= addAsset("Resources/Sprites/Alpha.png"					, 0, NULL, ASSET_GUI);
	//PIE
	assets[sPierceChit]			= addAsset("Resources/Sprites/Icons/PierceDam.png"			, 0, NULL, ASSET_GUI);
	assets[sImpactChit]			= addAsset("Resources/Sprites/Icons/ImpactDam.png"			, 0, NULL, ASSET_GUI);
	assets[sEnergyChit]			= addAsset("Resources/Sprites/Icons/EnergyDam.png"			, 0, NULL, ASSET_GUI);
	assets[sMetaChit]			= addAsset("Resources/Sprites/Icons/MetaSphere.png"			, 0, NULL, ASSET_GUI);
	assets[sScore]				= addAsset("Resources/Sprites/UI/ScoreBox.png"				, 0, NULL, ASSET_GUI);

	//Tutorials
	assets[tutControls]			= addAsset("Resources/Sprites/UI/Tutorials/Controls.png"	, 0, NULL, ASSET_GUI);
	assets[tutHelpControls]		= addAsset("Resources/Sprites/UI/Tutorials/Help Controls.png"	, 0, NULL, ASSET_GUI);
	assets[tutMusic]			= addAsset("Resources/Sprites/UI/Tutorials/Music.png"			, 0, NULL, ASSET_GUI);
	assets[tutInventory]		= addAsset("Resources/Sprites/UI/Tutorials/Inventory.png"	, 0, NULL, ASSET_GUI);
	assets[tutCrafting]			= addAsset("Resources/Sprites/UI/Tutorials/Crafting.png"	, 0, NULL, ASSET_GUI);
	assets[tutHealth]			= addAsset("Resources/Sprites/UI/Tutorials/Health.png"	, 0, NULL, ASSET_GUI);
	assets[tutWin]				= addAsset("Resources/Sprites/UI/Tutorials/Win.png"			, 0, NULL, ASSET_GUI);

	//Panels
#ifdef ALLOW_PRELOADING
	assets[sMainSplash]			= addAsset("Resources/Sprites/UI/Main Splash Alternate.png"	, 0, NULL, ASSET_GUI);
#else
	assets[sMainSplash]			= addAsset("Resources/Sprites/UI/Main Splash.png"			, 0, NULL, ASSET_GUI);
#endif

	assets[sMouseOver]			= addAsset("Resources/Sprites/UI/MouseOverPanel.png"		, 0, NULL, ASSET_GUI);
	assets[sTransChatBox]		= addAsset("Resources/Sprites/UI/ChatBox.png"				, 0, NULL, ASSET_GUI);
	assets[multiplayerMenu]		= addAsset("Resources/Sprites/UI/Multiplayer.png"			, 0, NULL, ASSET_GUI);
	assets[craftingMenu]		= addAsset("Resources/Sprites/UI/Crafting.png"				, 0, NULL, ASSET_GUI);
	assets[InventoryMenu]		= addAsset("Resources/Sprites/UI/Inventory.png"				, 0, NULL, ASSET_GUI);
	assets[controlsMenu]		= addAsset("Resources/Sprites/UI/ControlsMenu.png"			, 0, NULL, ASSET_GUI);
	assets[miniSquare]			= addAsset("Resources/Sprites/UI/Square.png"				, 0, NULL, ASSET_GUI);
	//Input
	assets[sTransInput8x2]		= addAsset("Resources/Sprites/UI/ShadedBox.png"				, 0, NULL, ASSET_GUI);
	assets[sIPInputBox]			= addAsset("Resources/Sprites/UI/IPBox.png"					, 0, NULL, ASSET_GUI);

	//Buttons
	assets[menuButton]			= addAsset("Resources/Sprites/UI/Button.png"				, 0, NULL, ASSET_GUI);
}
void GUI_Handler::initList(menuSet List, int size)
{
	//Allocates space for the list so we don't have to later.
	gui_icon* BlankIcon;
	for(int i = 0; i < size; i++)
	{
		BlankIcon = new gui_icon;
		((gui_panel*)(BlankIcon))->init(assets[sAlpha],Vector2D(0,0),STATE_GAME_INVENTORY);
		List.push(BlankIcon);
		Engine::Ins()->dlHandler.AddObject(List[i], DRAW_GUI);
	}
}
//=====MENUS
void GUI_Handler::initIntroMenu()
{
	//For a text box it's X location, Y location, width and height. If the box is to small it won't show

	gui_panel* networkSelect = new gui_panel();
	networkSelect->init(assets[sMainSplash],Vector2D((g_scrWidth/2)-512,(g_scrHeight/2)-280),STATE_INTRO_MENU);
	menuList.push(networkSelect);

	gui_panel* networkError = new gui_panel();
	networkError->init(assets[multiplayerMenu],Vector2D(0, 0),STATE_NETWORK_CANT_CONNECT);
	networkError->addTextBox(Quad(80, 250, 200, 20), "Unable to resolve Host IP");
	errorMessageIndex = menuList.push(networkError);

	gui_button* errorConfirm = new gui_button();
	errorConfirm->init(assets[menuButton], STATE_NETWORK_CANT_CONNECT, Quad(50, 250, 32, 32), BUTTON_ERROR_CONFIRM);
	menuList.push(errorConfirm);

	gui_button* singleSelect = new gui_button();
	singleSelect->init(assets[menuButton], STATE_INTRO_MENU, Quad((g_scrWidth/2)- 470, 135, 32, 32), BUTTON_SINGLEPLAYER);
	menuList.push(singleSelect);

#ifdef ALLOW_PRELOADING

	gui_button* preLoad = new gui_button();
	preLoad->init(assets[menuButton], STATE_INTRO_MENU, Quad((g_scrWidth/2)- 470, 200, 32, 32), BUTTON_PRELOAD);
	menuList.push(preLoad);

	gui_button* multiSelect  = new gui_button();
	multiSelect->init(assets[menuButton], STATE_INTRO_MENU, Quad((g_scrWidth/2) - 470, 270, 32, 32), BUTTON_MULTIPLAYER);
	menuList.push(multiSelect);
#else
	gui_button* multiSelect  = new gui_button();
	multiSelect->init(assets[menuButton], STATE_INTRO_MENU, Quad((g_scrWidth/2) - 470, 235, 32, 32), BUTTON_MULTIPLAYER);
	menuList.push(multiSelect);
#endif
}
void GUI_Handler::initLoadMultiGameMenu()
{
	gui_panel* networkSelect1 = new gui_panel();
	networkSelect1->init(assets[multiplayerMenu],Vector2D((g_scrWidth/2)-512,(g_scrHeight/2)-280),STATE_MULTI_GAME_SELECT);
	networkSelect1->addTextBox(Quad(short(g_scrWidth*0.5)- 470,325,100, 20),"IP ADDRESS");
	menuList.push(networkSelect1);


	gui_input* ipInput			= new gui_input();
	ipInput->init(assets[sIPInputBox],Quad(short(g_scrWidth*0.5)- 470,340,130,30),STATE_MULTI_GAME_SELECT,&mBox[IPADDRESS]);
	menuList.push(ipInput);

	//setMessage("127.0.0.1", IPADDRESS);

	gui_button* serverSelect	= new gui_button();
	serverSelect->init(assets[menuButton], STATE_MULTI_GAME_SELECT, Quad((g_scrWidth/2)- 470, 135, 32, 32), BUTTON_SERVER);
	menuList.push(serverSelect);

	gui_button* clientSelect	= new gui_button();
	clientSelect->init(assets[menuButton], STATE_MULTI_GAME_SELECT,  Quad((g_scrWidth/2) - 470, 235,32, 32), BUTTON_CLIENT);
	menuList.push(clientSelect);
}
void GUI_Handler::initGamePlayMenu()
{

	for(int i = 0; i < 3 ; i++)
	{
		gui_panel* PIEDock	= new gui_panel();
		PIEDock->init(assets[miniSquare],Vector2D(int((g_scrWidth/2) - 80 + (32*i)),0),STATE_GAME);
		menuList.push(PIEDock);
	}

	//=====Score 
	gui_panel* ScoreText = new gui_panel();
	ScoreText->init(assets[sScore],Vector2D(),STATE_GAME);
	ScoreText->addTextBox(Quad(6,10,100, 20),"Score: ");
	menuList.push(ScoreText);


	gui_input* scoreVal = new gui_input();
	scoreVal->init(assets[sAlpha],Quad(45,0,100, 20),STATE_GAME,&mBox[SCORE]);
	menuList.push(scoreVal);

	//=====Notifications
	gui_panel* NotifierBox = new gui_panel();
	NotifierBox->init(assets[sIPInputBox],Vector2D(g_scrWidth-263,g_scrHeight-60),STATE_GAME);
	menuList.push(NotifierBox);


	gui_input* Notifier = new gui_input();
	Notifier->init(assets[sAlpha],Quad(g_scrWidth-258,g_scrHeight-60,300, 20),STATE_GAME,&mBox[NOTIFICATION]);
	menuList.push(Notifier);

	//=====PIE
	pierceHUD	= new gui_panel();
	pierceHUD->init(assets[sPierceChit],Quad(int((g_scrWidth/2) - 80 + (32*0)),0,32,32),STATE_GAME);
	menuList.push(pierceHUD);

	impactHUD	= new gui_panel();
	impactHUD->init(assets[sImpactChit],Quad(int((g_scrWidth/2) - 80 + (32*1)),0,32,32),STATE_GAME);
	menuList.push(impactHUD);

	energyHUD	= new gui_panel();
	energyHUD->init(assets[sEnergyChit],Quad(int((g_scrWidth/2) - 80 + (32*2)),0,32,32),STATE_GAME);
	menuList.push(energyHUD);

	metaHUD	= new gui_panel();
	metaHUD->init(assets[sMetaChit],Quad(int((g_scrWidth/2) - 80 + (32*3)),0,32,32),STATE_GAME);
	menuList.push(metaHUD);


	//=====Chatbox
	Vector2D Pos (0,g_scrHeight-(256+32));
	gui_panel* inGamePlay= new gui_panel();
	gui_input* outputBox = new gui_input();
	inGamePlay->init(assets[sTransChatBox],Pos,STATE_GAME);
	outputBox->init(assets[sAlpha],Quad(short(Pos.x+10),short(Pos.y+10),500,600),STATE_GAME,&m_WorldText.Message);
	menuList.push(outputBox);
	menuList.push(inGamePlay);

}
void GUI_Handler::initControlsMenu()
{
	gui_panel* controls	= new gui_panel();
	controls->init(assets[controlsMenu],Vector2D(float(g_scrWidth*0.1),float(g_scrHeight*0.1)),STATE_GAME_CONTROLS);
	menuList.push(controls);
}
void GUI_Handler::initTutorialMenu()
{
	gui_tutorial* Controls = new gui_tutorial();
	Controls->init(assets[tutControls],Vector2D((g_scrWidth/2)-512,(g_scrHeight/2)-330),STATE_GAME,4);
	Tutorials.push(Controls);

	gui_tutorial* HelpControls = new gui_tutorial();
	HelpControls->init(assets[tutHelpControls],Vector2D((g_scrWidth/2)-512,(g_scrHeight/2)-330),STATE_GAME,4);
	Tutorials.push(HelpControls);

	gui_tutorial* Music = new gui_tutorial();
	Music->init(assets[tutMusic],Vector2D((g_scrWidth/2)-512,(g_scrHeight/2)-330),STATE_GAME,4);
	Tutorials.push(Music);

	gui_tutorial* Inventory = new gui_tutorial();
	Inventory->init(assets[tutInventory],Vector2D((g_scrWidth/2)-312,(g_scrHeight/2)-330),STATE_GAME,5);
	Tutorials.push(Inventory);

	gui_tutorial* Crafting = new gui_tutorial();
	Crafting->init(assets[tutCrafting],Vector2D((g_scrWidth/2)-112,(g_scrHeight/2)-330),STATE_GAME,5);
	Tutorials.push(Crafting);

	gui_tutorial* Health = new gui_tutorial();
	Health->init(assets[tutHealth],Vector2D((g_scrWidth/2)-312,(g_scrHeight/2)-330),STATE_GAME,5);
	Tutorials.push(Health);

	gui_tutorial* Winning = new gui_tutorial();
	Winning->init(assets[tutWin],Vector2D((g_scrWidth/2)-512,(g_scrHeight/2)-330),STATE_GAME,5);
	Tutorials.push(Winning);
};
void GUI_Handler::initGameChatMenu()
{
	gui_panel* inGamePlay	= new gui_panel();
	gui_panel* chatNotify	= new gui_panel();
	gui_input* chatBox		= new gui_input();
	gui_input* outputBox	= new gui_input();

	Vector2D Pos (0,g_scrHeight-(256+32));

	inGamePlay->init(assets[sTransChatBox],Pos,STATE_GAME_CHAT);
	chatBox->init(assets[sTransInput8x2],Quad(short(Pos.x),short(Pos.y+225),500,30),STATE_GAME_CHAT,&mBox[CHATBOXINPUT]);
	outputBox->init(assets[sAlpha],Quad(short(Pos.x+10),short(Pos.y+10),500,600),STATE_GAME_CHAT,&m_WorldText.Message);

	menuList.push(inGamePlay);
	menuList.push(chatBox);
	menuList.push(outputBox);
}
void GUI_Handler::initGameInventory(){

	gui_panel* inventoryMain	= new gui_panel();
	inventoryMain->init(assets[InventoryMenu],Vector2D(float(g_scrWidth*0.1),float(g_scrHeight*0.1)),STATE_GAME_INVENTORY);
	menuList.push(inventoryMain);

	//=====Notifications
	gui_panel* NotifierBox = new gui_panel();
	NotifierBox->init(assets[sIPInputBox],Vector2D(g_scrWidth-263,g_scrHeight-60),STATE_GAME_INVENTORY);
	menuList.push(NotifierBox);

	gui_input* Notifier = new gui_input();
	Notifier->init(assets[sAlpha],Quad(g_scrWidth-258,g_scrHeight-60,300, 20),STATE_GAME_INVENTORY,&mBox[NOTIFICATION]);
	menuList.push(Notifier);

	//=====AUTOLOOTING
	
	gui_button* ToggleAutoLoot = new gui_button();
	ToggleAutoLoot->init(assets[menuButton], STATE_GAME_INVENTORY, Quad(short(g_scrWidth*0.7),short(g_scrHeight*0.75), 32, 32), BUTTON_TOGGLE_AUTOLOOT);
	menuList.push(ToggleAutoLoot);

	gui_input* AutoLoot = new gui_input();
	AutoLoot->init(assets[sAlpha],Quad(short(g_scrWidth*0.75),short(g_scrHeight*0.75),300, 20),STATE_GAME_INVENTORY,&mBox[AUTOLOOTINFO]);
	menuList.push(AutoLoot);

};		//STATE_GAME_INVENTORY
void GUI_Handler::initGameCrafting(){

	gui_panel* craftBox	= new gui_panel();
	craftBox->init(assets[craftingMenu],Vector2D(float(g_scrWidth*0.1),float(g_scrHeight*0.1)),STATE_GAME_CRAFT);
	menuList.push(craftBox);
	//=====Notifications
	gui_panel* NotifierBox = new gui_panel();
	NotifierBox->init(assets[sIPInputBox],Vector2D(g_scrWidth-263,g_scrHeight-60),STATE_GAME_CRAFT);
	menuList.push(NotifierBox);


	gui_input* Notifier = new gui_input();
	Notifier->init(assets[sAlpha],Quad(g_scrWidth-258,g_scrHeight-60,300, 20),STATE_GAME_CRAFT,&mBox[NOTIFICATION]);
	menuList.push(Notifier);
}

/*=====PRIVATE UPDATES=====*/
void GUI_Handler::handleMultiGameMessages()
{

	if(strLength(mBox[IPADDRESS]) < 20 && Message != KEY_BACK && Message != NULL)
	{
		append(mBox[IPADDRESS],Message,512); 
	}
	if(Message == KEY_BACK)		removeLast(mBox[IPADDRESS]); 	
	if(Message == KEY_ENTER){
		removeLast(mBox[IPADDRESS]); 
		lastButtonClicked = BUTTON_CLIENT;
		needToUpdate = true;
	}
};
void GUI_Handler::handleGameChatMessage(){

	switch(Message)
	{
	case KEY_BACK:	removeLast(mBox[CHATBOXINPUT]);		break;
	case KEY_ENTER:
		enterMessage();
		break;
	default:
		if(strLength(mBox[CHATBOXINPUT]) < 40)
		{
			char* temp = combine(mBox[CHATBOXINPUT],&Message); 
			delete mBox[CHATBOXINPUT];
			mBox[CHATBOXINPUT] = temp;
		}
		else
		{
			char* temp = combine(mBox[CHATBOXINPUT]," (cont...)"); 
			delete mBox[CHATBOXINPUT];
			mBox[CHATBOXINPUT] = temp;

			enterMessage();	

			temp = combine(mBox[CHATBOXINPUT],&Message); 
			delete mBox[CHATBOXINPUT];
			mBox[CHATBOXINPUT] = temp;
		}//End else
		break;
	}

};
void GUI_Handler::handleInGameMessage (){

	int mesgItoA = -1;

	switch(Message)
	{
	case '1':	mesgItoA = 1;	break;
	case '2':	mesgItoA = 2;	break;
	case '3':	mesgItoA = 3;	break;
	case '4':	mesgItoA = 4;	break;
	case '5':	mesgItoA = 5;	break;
	case '6':	mesgItoA = 6;	break;
	case '7':	mesgItoA = 7;	break;
	case '8':	mesgItoA = 8;	break;
	case '9':	mesgItoA = 9;	break;
	case '0':	mesgItoA = 0;	break;

	}
	if(mesgItoA != -1){
		needToUpdate = true;
		playerInvMessage.y = 0.0f;
		playerInvMessage.z = INVENTORY;

	}

};

void GUI_Handler::handleMessages(short currentState){

	if(Message != '~')
	{
		needToUpdate = true;
		switch(currentState)
		{
		case STATE_MULTI_GAME_SELECT:	handleMultiGameMessages();		break;	
		case STATE_GAME_CHAT:			handleGameChatMessage();		break;
		case STATE_GAME:				handleInGameMessage();			break;
		}
	}
	Message = '~';
};
char* GUI_Handler::generateInventoryMouseOverText(Item_Base* Item)
{
	string hoverText = Item->itemName;

	switch(Item->itemType)
	{
	case ITEM_EQUIPPABLE:
		{
			Item_Equippable* tEquippable = ((Item_Equippable*)(Item));
			if(tEquippable->getPIE().x > 0 || tEquippable->getPIE().y > 0 || tEquippable->getPIE().z > 0) //If this has a pie value, show it.
				hoverText = hoverText 
				+ "\nPierce: " + wmIntegerToString(int(tEquippable->getPIE().x))
				+ "\nImpact: " + wmIntegerToString(int(tEquippable->getPIE().y))
				+ "\nEnergy: " + wmIntegerToString(int(tEquippable->getPIE().z));
		}
		break;
	case ITEM_CONSUMABLE:
		{
			Item_Consumable* tConsumable = ((Item_Consumable*)(Item));
			for(int x = 0; x < tConsumable->effects.curElements; x++)	//For every effect of the item
			{
				hoverText = hoverText +	"\n" 
					+ statNames[tConsumable->effects.buffList[x].statToAffect] + ": " 
					+ wmIntegerToString(tConsumable->effects.buffList[x].amount);
			}
			hoverText = hoverText + "\nUses Left: " + wmIntegerToString(int(tConsumable->usesLeft));
			hoverText = hoverText + "\nDuration:  " + wmIntegerToString(tConsumable->effects.duration);
		}
		break;
	}
	return wordModify::copy(hoverText);
}
char* GUI_Handler::generateRecipeMouseOverText(Item_Base* Item, int Index)
{
	string hoverText = generateInventoryMouseOverText(Item);

	hoverText = hoverText + "\n\nRecipe:";

	for(int r = 0; r < 4; r++)
		hoverText = hoverText + "\n" +   Factory::get().getRecipe(Index,r);

	return wordModify::copy(hoverText);
}
bool GUI_Handler::handleMouseOver(short currentState, gui_panel* Piece, POINT mouse)
{
	if(Piece->checkCollision(mouse))
		return true;
	return false;
}
bool GUI_Handler::handleMouseOver(short currentState, menuSet List, POINT mouse)
{
#define guiList ((gui_icon*)(Inventory[i]))
	Quad DIM(short(mouse.x),short(mouse.y),1280,256);
	Quad TDIM(short(mouse.x+5),short(mouse.y+5),1280,256);
	for(int i = 0; i < List.size(); i++)
	{
		if(((gui_panel*)(List[i]))->checkCollision(mouse))
		{
			setMessage(((gui_icon*)(List[i]))->hoverText,MOUSEOVER);
			mouseOverPanel->reset(DIM,currentState);
			mouseOverPanel->modifyTBox(TDIM,mBox[MOUSEOVER],0);
			mouseOverPanel->assetIndex = assets[sMouseOver];
			return true;
		}
		else
		{
			setMessage(" ",MOUSEOVER);
			mouseOverPanel->assetIndex = assets[sAlpha];
			mouseOverPanel->reset(DIM,currentState);
			mouseOverPanel->modifyTBox(DIM,mBox[MOUSEOVER],0);
		}

	}
	return false;
};
void GUI_Handler::handlePIEMouseOver(short currentState, POINT Mouse)
{
	//Here the ridiculously long string is loaded into memory in case any of the textboxes are moused over. If they are then that string is shown.
	string hoverText;
	Quad DIM(short(Mouse.x),short(Mouse.y),1280,256);
	Quad TDIM(short(Mouse.x+5),short(Mouse.y+5),1280,256);

	if(handleMouseOver(currentState,pierceHUD,Mouse))
	{
		hoverText = hoverText 
			+"     Pierce " 
			+ "\n\nDamage:     " +  wmIntegerToString(int(playerDamage.x)) 
			+ "\n\nDefence:    " +  wmIntegerToString(int(playerDefenses.x)) 
			+ "\n\nMax Health: " +  wmIntegerToString(int(playerHealth.x)) ; 
		setMessage(copy(hoverText),MOUSEOVER);
		mouseOverPanel->reset(DIM,currentState);
		mouseOverPanel->modifyTBox(TDIM,mBox[MOUSEOVER],0);
		mouseOverPanel->assetIndex = assets[sMouseOver];
		return;
	}
	if(handleMouseOver(currentState,impactHUD,Mouse))
	{
		hoverText = hoverText 
			+"     Impact " 
			+ "\n\nDamage:     " +  wmIntegerToString(int(playerDamage.y)) 
			+ "\n\nDefence:    " +  wmIntegerToString(int(playerDefenses.y)) 
			+ "\n\nMax Health: " +  wmIntegerToString(int(playerHealth.y)) ;
		setMessage(copy(hoverText),MOUSEOVER);
		mouseOverPanel->reset(DIM,currentState);
		mouseOverPanel->modifyTBox(TDIM,mBox[MOUSEOVER],0);
		mouseOverPanel->assetIndex = assets[sMouseOver];
		return;
	}
	if(handleMouseOver(currentState,energyHUD,Mouse))
	{
		hoverText = hoverText 
			+"     Energy " 
			+ "\n\nDamage:     " +  wmIntegerToString(int(playerDamage.z)) 
			+ "\n\nDefence:    " +  wmIntegerToString(int(playerDefenses.z)) 
			+ "\n\nMax Health: " +  wmIntegerToString(int(playerHealth.z)) ;
		setMessage(copy(hoverText),MOUSEOVER);
		mouseOverPanel->reset(DIM,currentState);
		mouseOverPanel->modifyTBox(TDIM,mBox[MOUSEOVER],0);
		mouseOverPanel->assetIndex = assets[sMouseOver];
		return;
	}
	if(handleMouseOver(currentState,metaHUD,Mouse))
	{
		setMessage("Mana",MOUSEOVER);
		mouseOverPanel->reset(DIM,currentState);
		mouseOverPanel->modifyTBox(TDIM,mBox[MOUSEOVER],0);
		mouseOverPanel->assetIndex = assets[sMouseOver];
		return;
	}

	setMessage(" ",MOUSEOVER);
	mouseOverPanel->assetIndex = assets[sAlpha];
	mouseOverPanel->reset(DIM,currentState);
	mouseOverPanel->modifyTBox(DIM,mBox[MOUSEOVER],0);

}
void GUI_Handler::updateList(short currentState,short listID,  Vector<gui_base*> toUpdate)
{
	for(int i = 0; i < toUpdate.size(); i++)
	{
		switch(toUpdate[i]->getMorph())
		{
		default:																		break;
		case MORPH_NULL:																break;
		case MORPH_PANEL:		((gui_panel*)(toUpdate[i]))->update(currentState);		break;
		case MORPH_INPUT:		((gui_input*)(toUpdate[i]))->update(currentState);		break;
		case MORPH_TUTORIAL:	
			{
				bool next = ((gui_tutorial*)(toUpdate[currentTutorial]))->update(currentState);
				if(next && currentTutorial + 1 < Tutorials.size())
					currentTutorial++;
			}
			break;
		case MORPH_ICON:
			if(((gui_button*)(toUpdate[i]))->isPressed())
			{
				playerInvMessage.x = float(((gui_icon*)(toUpdate[i]))->buttonID());
				playerInvMessage.y = ((gui_button*)(toUpdate[i]))->valuePressed();
				playerInvMessage.z = listID;
				((gui_button*)(toUpdate[i]))->resetPressed();
			}
			((gui_button*)(toUpdate[i]))->update(currentState);
			break;
		case MORPH_BUTTON:	
			if(((gui_button*)(toUpdate[i]))->isPressed())
			{
				lastButtonClicked = ((gui_button*)(toUpdate[i]))->buttonID();
				((gui_button*)(toUpdate[i]))->resetPressed();
			}
			((gui_button*)(toUpdate[i]))->update(currentState);
			break;

		}//End switch(menuList[i]->getMorph())
	}//End for(int i = 0; i < menuList.size(); i++)	
};
/*=====PRIVATE MESSAGE HANDLING=====*/
void GUI_Handler::addWorldMessage(char* Message)
{
	m_WorldText.addMessage(Message);
}
char* GUI_Handler::preparePlayerPrefix(int index)
{
	int size = 11;
	char* start = "Player ";
	char* prefix = new char[size];
	copyIntoExisting(prefix, start);
	prefix[size-4] = (char)(((int)'0')+index+1);
	prefix[size-3] = ':';
	prefix[size-2] = ' ';
	prefix[size-1] = '\0';

	return prefix;
}
char* GUI_Handler::polishMultiplayerMessage(char* message)
{
	Networking* pNetwork = &Engine::Ins()->game.m_network;
	char* prefix = NULL, * output;
	prefix = preparePlayerPrefix(pNetwork->getClientIndex());
	output = combine(prefix, message);

	int result = pNetwork->MakeServerRequest(NETWORK_REQUEST_CHATBOX_ADD_MESSAGE,
		copy(output), strLength(output)+1);

	delete prefix;
	assert(result != NETWORK_ERR_INVALID_DATA);
	return output;
}
void GUI_Handler::enterMessage()
{
	char* message = NULL;
	Networking* pNetwork = &Engine::Ins()->game.m_network;

	// add the "Player x: " prefix to the message if it's a multiplayer game
	// otherwise copy directly from the input box
	if(pNetwork->isInitialized())
		message = polishMultiplayerMessage(mBox[CHATBOXINPUT]);
	else 
		message = copy(mBox[CHATBOXINPUT]);

	m_WorldText.addMessage(copy(message));

	wipe(mBox[CHATBOXINPUT]);
	delete message;

}
//=====CORE FUNCTIONS
void GUI_Handler::initialize()
{
	//Variables
	Message = '~';

	for(int i = 0; i < SIZE_MESSAGES; i++)
	{
		mBox[i] = new char [512];
		mBox[i][0] = '\0';
	}


	needToUpdate		= true;
	refreshInventory	= true;
	lastButtonClicked = NOBUTTON;
	lastGameState = -1;
	currentTutorial = 0;
	playerInvMessage.x = -1;
	playerInvMessage.y = -1;
	playerInvMessage.z = -1;

	notificationCheck.init(1000);
	waitAStepToUndoNotification = false;
	//Functions
	m_WorldText.init();
	initAssets();
	initIntroMenu();
	initLoadMultiGameMenu();
	initGamePlayMenu();
	initControlsMenu();
	initTutorialMenu();
	initGameChatMenu();
	initGameInventory();
	initGameCrafting();
	for(int i = 0; i < menuList.size(); i++)
		Engine::Ins()->dlHandler.AddObject(TbMenuList, DRAW_GUI);


	initList(Inventory,maxInventoryMenu);
	initList(Equipment,maxEquipmentMenu);
	initList(CrafTable,maxCrafTableMenu);
	initList(CraftRecipes,maxCrafTableMenu);
	initList(Tutorials,10);

	mouseOverPanel = new gui_panel();
	mouseOverPanel->init(assets[sAlpha],Vector2D(0,0),STATE_GAME_INVENTORY);
	mouseOverPanel->addTextBox(Quad(50,10,500,2048),mBox[MOUSEOVER]);
	menuList.push(((gui_base*)(mouseOverPanel)));

	Engine::Ins()->dlHandler.AddObject(mouseOverPanel, DRAW_GUI);
}
void GUI_Handler::update(short currentState,POINT mouse)
{
	if(lastGameState != currentState)
	{
		needToUpdate	= true;
		lastGameState	= currentState;
	}

	handleMessages(currentState);

	if(needToUpdate)
	{
		lastButtonClicked = NOBUTTON;
		playerInvMessage = Vector3D(-1,-1,-1);

		updateList(currentState,NULL,menuList);
		updateList(currentState,INVENTORY,Inventory);
		updateList(currentState,EQUIPMENT,Equipment);
		updateList(currentState,CRAFTABLE,CrafTable);
		updateList(currentState,CRAFTABLE,CraftRecipes);
		updateList(currentState,NULL,Tutorials);

	}


	switch(currentState)
	{
	case STATE_GAME:
		handlePIEMouseOver(currentState,mouse);
		break;
	case STATE_GAME_INVENTORY:	
		if(!handleMouseOver(currentState,Inventory,mouse))	
			handleMouseOver(currentState,Equipment,mouse);	
		break;
	case STATE_GAME_CRAFT:	
		if(!handleMouseOver(currentState,CraftRecipes,mouse))	
			handleMouseOver(currentState,CrafTable,mouse);	
		break;

	};
	if(!Engine::Ins()->game.m_network.isInitialized())
		deactivateChatbox();
	
	if(notificationCheck.update())
	{
		if(waitAStepToUndoNotification)
			waitAStepToUndoNotification = false;
		else
			setMessage("",NOTIFICATION);
	}




	needToUpdate = false;
};
void GUI_Handler::release()
{
	for(int i = 0; i < SIZE_MESSAGES; i++){
		delete mBox[i];
		mBox[i] = NULL;
	}
	menuList.clear();
	Inventory.clear();
	Equipment.clear();
	CrafTable.clear();
	m_WorldText.release();
};
//=====MUTATORS
void GUI_Handler::checkIconCollision(short currentState, menuSet List, POINT mouse, bool shiftClicked)
{
	for(int i(0) ; i < List.size(); i++)
		if(List[i]->getMorph() == MORPH_ICON)
			if(((gui_button*)(List[i]))->checkClicked(mouse))
			{
				if(shiftClicked)
				{
					((gui_button*)(List[i]))->shiftPressed();
					setMessage("Item Removed",NOTIFICATION);
					Engine::Ins()->sound.PlayCue("Smash");
				}
				else
					Engine::Ins()->sound.PlayCue("click");
				refreshInventory = true;
			}
}
void GUI_Handler::checkCollision(short currentState,POINT mouse, bool shiftClicked)
{
	needToUpdate = true;
	for(int i = 0; i < menuList.size(); i++)
		if(menuList[i]->getMorph() == MORPH_BUTTON)
			TbMenuList->checkClicked(mouse);

	checkIconCollision(currentState, Inventory,mouse,shiftClicked);
	checkIconCollision(currentState, Equipment,mouse,false);
	checkIconCollision(currentState, CrafTable,mouse,false);
};
void GUI_Handler::setMessage(char a_message)
{
	Message = a_message;
}
void GUI_Handler::setMessage(char* a_message,messageSets list){

	if(list == NOTIFICATION)
		waitAStepToUndoNotification = true;

	switch(list){
	case CHATBOXOUTPUT:	addWorldMessage(copy(a_message));	break;
	default: 
		if(mBox[list])	
		{
			delete mBox[list];
			mBox[list] = new char [512];
			mBox[list][0] = '\0';
		}
		copyIntoExisting(mBox[list] ,a_message);	
		break;

	}
	needToUpdate = true;

}
void GUI_Handler::setMessage(int foreValue, char* appendedMessage,messageSets list)
{
	string appendedValue;
	appendedValue = wmIntegerToString(foreValue);
	appendedValue = appendedValue + appendedMessage;
	setMessage(wordModify::copy(appendedValue),list);
};
void GUI_Handler::setMessage(char* foreValue, char* appendedMessage,messageSets list)
{
	string appendedValue;
	appendedValue = foreValue;
	appendedValue = appendedValue + appendedMessage;
	setMessage(wordModify::copy(appendedValue),list);
};

void GUI_Handler::clearMessage(messageSets list)
{
	if(list == CHATBOXOUTPUT)
	{
		m_WorldText.release();
		m_WorldText.init();
	}
	else
	{
		delete mBox[list];
		mBox[list] = NULL;
	}

}

void GUI_Handler::changeTextBoxString(int index, char* a_message)
{
	gui_panel* gui = (gui_panel*)menuList[index];
	gui->modifyText(a_message);
}
//====Health
void GUI_Handler::setPIE(Vector3D PIE)
{
	//pierceHUD
	color PierceColor(int((PIE.x/100)*255),200 - int((PIE.x/100)*255),0);
	Engine::Ins()->graphics.ChangeAssetColorKey(pierceHUD->assetIndex,PierceColor);

	color ImpactColor(int((PIE.y/100)*255),200 - int((PIE.y/100)*255),0);
	Engine::Ins()->graphics.ChangeAssetColorKey(impactHUD->assetIndex,ImpactColor);

	color EnergyColor(int((PIE.z/100)*255),200 - int((PIE.z/100)*255),0);
	Engine::Ins()->graphics.ChangeAssetColorKey(energyHUD->assetIndex,EnergyColor);

};
void GUI_Handler::setMeta(float percentBlue)
{
	metaHUD->setScale(float(percentBlue*.01),float(percentBlue*.01),0.0f);
	color metaColor(10,10+int(percentBlue),10+int((percentBlue/100)*220));
	Engine::Ins()->graphics.ChangeAssetColorKey(metaHUD->assetIndex,metaColor);
}
void GUI_Handler::setMaxHealth(Vector3D Health)
{
	playerHealth = Health;
}
void GUI_Handler::setDamage(Vector3D Damage)
{
	playerDamage = Damage;
}
void GUI_Handler::setDefenses(Vector3D Defenses)
{
	playerDefenses = Defenses;
}
//===Chatbox
void GUI_Handler::deactivateChatbox()
{
	for(int i = 0; i < menuList.size();i++)
		if(menuList[i]->assetIndex.y == assets[sTransChatBox].y)	menuList[i]->active = false;

}
//===Inventory
void GUI_Handler::setInventory(itemList a_Inventory)
{
#define xOffset	short(g_scrWidth*.325)
#define yOffset (g_scrHeight/2)-(256-47)
#define shiftAdd 32
#define maxXSlots 13*shiftAdd
#define guiList ((gui_icon*)(Inventory[i]))

	Quad Pos(xOffset,yOffset,shiftAdd,shiftAdd);
	for(int i = 0; i < Inventory.size(); i++)
		guiList->init(assets[sAlpha],STATE_GAME_INVENTORY,Quad(0,0,0,0),i);

	for(int i = 0; i < a_Inventory.size(); i++)
	{
		guiList->init(a_Inventory[i]->iconAsset, STATE_GAME_INVENTORY,Pos,i);
		guiList->setScale(a_Inventory[i]->getScale());
		guiList->hoverText = generateInventoryMouseOverText(a_Inventory[i]);

		if((Pos.x +=shiftAdd) > (xOffset + maxXSlots))
		{
			Pos.x = xOffset;
			Pos.y += shiftAdd;
		}
	}

#undef xOffset
#undef yOffset
#undef shiftAdd
#undef maxXSlots
#undef guiList
};
void GUI_Handler::setRecipeList(Vector<gui_base*> &RecipeList)
{
#define xOffset	short(g_scrWidth  * 0.14)
#define yOffset short(g_scrHeight * 0.15)
#define shiftAdd 32
#define maxXSlots 5*shiftAdd

	Item_Base* itemToGui[Factory::ITEM_SIZE];

	Factory::get().getOriginalCopies(itemToGui);


	Quad Pos(xOffset,yOffset,shiftAdd,shiftAdd);
	string hoverText;


	for(int i = Factory::bowieKnife, x = 0; i < Factory::ITEM_SIZE; i++,x++)
	{
		((gui_icon*)(RecipeList[x]))->init(assets[sAlpha],STATE_GAME_CRAFT,Quad(6000,6000,0,0),x);
		((gui_icon*)(RecipeList[x]))->init(itemToGui[i]->iconAsset, STATE_GAME_CRAFT,Pos,Factory::get().getAssetEnum(itemToGui[i]));
		((gui_icon*)(RecipeList[x]))->hoverText = generateRecipeMouseOverText(itemToGui[i],i);


		if(itemToGui[i]->itemType == ITEM_EQUIPPABLE 
			&&(((Item_Equippable*)(itemToGui[i]))->getEquipType() == FIST 
			|| ((Item_Equippable*)(itemToGui[i]))->getEquipType() == BOOT))
			i++;

		Pos.x +=shiftAdd;

		if((Pos.x +=shiftAdd) > (xOffset + maxXSlots))
		{
			Pos.x = xOffset;
			Pos.y += shiftAdd;
		}
	}


#undef xOffset
#undef yOffset
#undef shiftAdd
#undef maxXSlots
}
void GUI_Handler::setCrafTable(itemList a_Inventory){

#define xOffset	short(g_scrWidth  * 0.343)
#define yOffset short(g_scrHeight * 0.16)
#define shiftAdd 30
#define maxXSlots 13*shiftAdd
#define guiList ((gui_icon*)(CrafTable[i]))


	Vector<Item_Base*> itemToGui = Factory::get().createRecipeBook(a_Inventory);
	setRecipeList(CraftRecipes);
	Quad Pos(xOffset,yOffset,shiftAdd,shiftAdd);
	for(int i = 0; i < CrafTable.size(); i++)
		guiList->init(assets[sAlpha],STATE_GAME_CRAFT,Quad(0,0,0,0),i);

	for(int i = 0; i < itemToGui.size(); i++)
	{
		guiList->init(assets[sAlpha],STATE_GAME_CRAFT,Quad(6000,6000,0,0),i);
		guiList->init(itemToGui[i]->iconAsset, STATE_GAME_CRAFT,Pos,
			Factory::get().getAssetEnum(itemToGui[i]));
		guiList->hoverText = generateInventoryMouseOverText(itemToGui[i]);



		Pos.x +=shiftAdd;

		if((Pos.x +=shiftAdd) > (xOffset + maxXSlots))
		{
			Pos.x = xOffset;
			Pos.y += short(shiftAdd + shiftAdd*0.5);
		}
	}

	itemToGui.clear();
#undef xOffset
#undef yOffset
#undef shiftAdd
#undef maxXSlots
#undef guiList
};
void GUI_Handler::setEquipment(Item_Base* equipList[], int Size){

#define xOffset	short(g_scrWidth*.325)
#define yOffset (g_scrHeight/2)-17
#define maxXSlots 2*shiftAdd
#define shiftAdd 32

	Quad Pos(xOffset,yOffset,32,32);
	for(int i = 0; i < Size; i++)
		((gui_icon*)(Equipment[i]))->init(assets[sAlpha],STATE_GAME_INVENTORY,Quad(6000,6000,0,0),i);

	for(int i = 0; i < Size; i++)
	{
		if(equipList[i] != NULL)
		{
			((gui_icon*)(Equipment[i]))->init(equipList[i]->iconAsset, STATE_GAME_INVENTORY,Pos,i);
			((gui_icon*)(Equipment[i]))->hoverText = generateInventoryMouseOverText(equipList[i]);
		}
		Pos.x +=shiftAdd;
		if(i == Weaponry-1)
			Pos.x +=(2*shiftAdd);
	}

#undef xOffset
#undef yOffset
#undef shiftAdd
#undef maxXSlots
}
//===Tutorial
void GUI_Handler::resetTutorials()
{
	currentTutorial = 0;
	for(int i = 0; i < Tutorials.size(); i++)
		((gui_tutorial*)(Tutorials[i]))->reset();
}
void GUI_Handler::stopTutorials()
{
	currentTutorial = Tutorials.size();
	for(int i = 0; i < Tutorials.size(); i++)
		((gui_tutorial*)(Tutorials[i]))->stop();
}
//=====Multiplayer
char* GUI_Handler::getTextByIndex(messageSets index)
{
	switch(index)
	{
	case CHATBOXOUTPUT:	return m_WorldText.Message;	break;
	default:			return mBox[index];			break;

	}

	return "INVALID";
}